package com.zzx.threekingdom.model;

import com.zzx.threekingdom.card.BaseCard;
import com.zzx.threekingdom.card.Card;
import com.zzx.threekingdom.card.CardHeap;
import com.zzx.threekingdom.card.CardList;
import com.zzx.threekingdom.card.CharacterCard;
import com.zzx.threekingdom.card.EquipmentCard;
import com.zzx.threekingdom.card.KnowhowCard;
import com.zzx.threekingdom.card.Pattern;
import com.zzx.threekingdom.card.PatternCard;
import com.zzx.threekingdom.card.BaseCard.BaseCardType;
import com.zzx.threekingdom.card.KnowhowCard.KnowhowCardType;

import com.zzx.threekingdom.judge.Judge;
import com.zzx.threekingdom.judge.Rule;
import com.zzx.threekingdom.judge.Judge.*;
import com.zzx.threekingdom.judge.Rule.CardRule;
import com.zzx.threekingdom.judge.Rule.PlayerStep;
import com.zzx.threekingdom.view.NotifyHandler;
import com.zzx.threekingdom.view.PlayerEquipmentView;
import com.zzx.threekingdom.view.PlayerView;
import com.zzx.threekingdom.view.PlayerEquipmentView.EquipmentReplace;

import android.os.Handler;
import android.os.Message;

import java.util.ArrayList;

public abstract class AbsPlayerModel implements EquipmentReplace
{
    public interface JudgeListener { public void onJudgeChanged(ArrayList<ActionInfo> judgeArea); };
    
    
    
	abstract public void pickOneCharacter(CardList characterCards, IPassCard i);
    abstract public void pickTargetOneCard(ArrayList<CardList> cardss, IPassCard i);
    abstract public void selectAbondonCards(int num, IPassCards ipc);
    abstract public void onNeedActionByName(String name, IPassCard ipc, IPassAction ipa, ActionInfo askInfo);
    abstract public void askYesNo(String ask, IAskYesNo ia);
    
    
    
    
    public int health = 0;
    public boolean dead = false;
    public CardList handCards = new CardList();
    public PlayerView playeView;
    public Message waitingExitUseCardsMsg = null;
    private boolean hasUsedKill = false;
    private boolean waitingActiveUseDone = false;
    private Runnable waitingActiveUseDoneRunnable = null;
    private Handler mHandler = new Handler();
    private JudgeListener judgeListener = null;
    
    private ArrayList<ActionInfo> judgeArea = new ArrayList<ActionInfo>();
    private ArrayList<PlayerStep> jumpStep = new ArrayList<PlayerStep>();
    
    private NotifyHandler judgeNotifyHandler = new NotifyHandler() { public void onNotify() {
        if(judgeListener != null) judgeListener.onJudgeChanged(judgeArea);
    }};
    
    public AbsPlayerModel(PlayerView pv)
    {
        playeView = pv;
        playeView.setCards(handCards);
        playeView.getEquipmentView().setReplaceListener(this);
    }
    
    
    public void onActiveUseCards() {} 
    public void onOutOfTurn() {}
    public void onHintText(String hint) {}
    public void setStayWell() {}
    
    public boolean isDead() { return (dead==true); }
    public void setDead()
    {
        Judge.judge.addLog(getCharacterName() + "死亡");
        dead = true;
    }
    
    public int getHandCardsMaxNum() { return (health > 0)?health:0; }
    public int getShouldAbandonCardsNum()
    {
        int ret = 0;
        int handNum = handCards.size();
        int carryMax = getHandCardsMaxNum();
        if(handNum > carryMax)
        {
            return handNum - carryMax;
        }
        return ret;
    }
    
    public PlayerView getPlayerView() { return playeView; }
    public int getHealth() { return health; }
    public int getHealthMax() { return ((CharacterCard)playeView.getCharacterView().getCard()).getHealthMax(); }
    public void setHealth(int h) { health = h; playeView.getHealthView().setHealth(health);}
    public boolean isFullHealth() { return (((CharacterCard)playeView.getCharacterView().getCard()).getHealthMax() <= health); }
    public CardList getHandCards() { return handCards; }
    public EquipmentCard getWeapon() { return playeView.getEquipmentView().getWeapon(); }
    public EquipmentCard getArmor() { return playeView.getEquipmentView().getArmor(); }
    public EquipmentCard getPlusHorse() { return playeView.getEquipmentView().getPlusHorse(); }
    public EquipmentCard getMinusHorse() { return playeView.getEquipmentView().getMinusHorse(); }
    public boolean getHasUsedKill() { return hasUsedKill; }
    public void setHasUsedKill(boolean used) { hasUsedKill = used; }
    public void setWaitingActiveUseDone(boolean done) { waitingActiveUseDone = done; }
    public boolean getWaitingActiveUseDone() { return waitingActiveUseDone; }
    public void setJudgeListener(JudgeListener jl) { judgeListener = jl; }
    public ArrayList<PlayerStep> getJumpStep() { return jumpStep; }
    public void addJumpStep(PlayerStep step) { jumpStep.add(step); }
    public boolean hasCard() { return (handCards.size()!=0 || judgeArea.size() != 0 || getAllEuipment().size() != 0); }//enclude judge
    
    public ArrayList<CardList> getAllCards()
    {
    	ArrayList<CardList> ret = new ArrayList<CardList>();
    	ret.add(handCards);
    	ret.add(getAllEuipment());
    	return ret;
    }

    public void addHandCards(CardList playCards)
    {
        handCards.addCards(playCards);
    }
    
    public boolean addJudgeArea(ActionInfo act)
    {
    	for(int i = 0;i < judgeArea.size();i++)
    	{
    		if(act.getActionName().equals(act.getActionName()))
    		{
    			return false;
    		}
    	}
    	judgeArea.add(act);
    	judgeNotifyHandler.notifyListener();
    	return true;
    }
    
    public void removeJudgeArea(ActionInfo act) { judgeArea.remove(act); judgeNotifyHandler.notifyListener();}
    public void removeJudgeAreaByName(String actName)
    {
        for(int i = 0;i < judgeArea.size();i++)
        {
            if(judgeArea.get(i).getActionName().equals(actName))
                judgeArea.remove(i);
        }
        judgeNotifyHandler.notifyListener();
    }
    
    public ActionInfo getJudgeByName(String actName)
    {
        for(int i = 0;i < judgeArea.size();i++)
        {
            ActionInfo act = judgeArea.get(i);
            if(act.getActionName().equals(actName))
                return act;
        }
        return null;
    }
    
    public boolean hasEquipment(String name)
    {
        EquipmentCard card = getWeapon();
        if(card!=null&&card.getName().equals(name))
            return true;
        card = getArmor();
        if(card!=null&&card.getName().equals(name))
            return true;
        card = getPlusHorse();
        if(card!=null&&card.getName().equals(name))
            return true;
        card = getMinusHorse();
        if(card!=null&&card.getName().equals(name))
            return true;
        return false;
    }
    
    public CardList getAllEuipment()
    {
    	CardList ret = new CardList();
    	Card card = getWeapon();
    	if(card != null)
    		ret.add(card);
    	card = getArmor();
    	if(card != null)
    		ret.add(card);
    	card = getPlusHorse();
    	if(card != null)
    		ret.add(card);
    	card = getMinusHorse();
    	if(card != null)
    		ret.add(card);
    	
    	return ret;
    }
    
    public void drawEquipmentCard(EquipmentCard card)
    {
        if(card == getWeapon())
            playeView.getEquipmentView().addWeapon(null);
        else if(card == getArmor())
            playeView.getEquipmentView().addArmor(null);
        else if(card == getPlusHorse())
            playeView.getEquipmentView().addPlusHorse(null);
        else if(card == getMinusHorse())
            playeView.getEquipmentView().addMinusHorse(null);
        
    }
    
    public boolean drawCard(Card card)
    {
        if(card==null)
            return false;
        else if(handCards.contains(card))
            handCards.drawCard(card);
        else if(card instanceof EquipmentCard)
            drawEquipmentCard((EquipmentCard)card);
        else
            return false;
        return true;
    }
    
    public boolean drawCards(CardList cards)
    {
        boolean bRet = false;
        for(int i = 0;i < cards.size();i++)
        {
            if(drawCard(cards.get(i))==true)
                bRet = true;
        }
        return bRet;
    }
    
    public boolean drawHandCards(CardList playCards) { return handCards.drawCards(playCards); }
    
    public void setCharacter(CharacterCard card)
    {
        setHealth(card.getHealthMax());
        getPlayerView().setCharacter(card);
    }
    public String getCharacterName()
    {
        Card card = playeView.characterView.getCard();
        if((card != null)&&(card.getName()!=null))
            return card.getName();
        return "无名";
    }
    
    public int getCharacterAtkRange() { return Math.max(1, getPlayerView().getEquipmentView().getWeapon().getAtkRange()); }
    public int getAttackRange()
    {
        PlayerEquipmentView pev = getPlayerView().getEquipmentView();
        EquipmentCard equ = pev.getWeapon(); 
        return Math.max(1, equ!=null?equ.getAtkRange():1) + getDistanceFromMe();
    }
    public int getDistanceFromMe() { return (((getPlayerView().getEquipmentView().getMinusHorse())==null)?1:2); }
    public int getDistanceFromOthers() { return (((getPlayerView().getEquipmentView().getPlusHorse())==null)?1:2); }

    public ArrayList<AbsPlayerModel> getPmInRange(int attackRange) //except me
    {
        ArrayList<AbsPlayerModel> retPm = new ArrayList<AbsPlayerModel>();
        if(isDead()==false)
        {
            ArrayList<AbsPlayerModel> livePm = Judge.judge.getLivePmFromeMe(this);

            int myIndex = livePm.indexOf(this);

            for(int i = 0;i < livePm.size();i++)
            {
                AbsPlayerModel pm = livePm.get(i);
                if((pm!=this)&&(retPm.contains(pm)==false))
                {
                    int dis = Math.abs(myIndex - i);
                    if(attackRange >= (dis + pm.getDistanceFromOthers()))
                    {
                        retPm.add(pm);
                    }
                }
            }
            
            for(int i = livePm.size() - 1;i >=0;i--)
            {
                AbsPlayerModel pm = livePm.get(i);
                if((pm!=this)&&(retPm.contains(pm)==false))
                {
                    int dis = Math.abs(myIndex - i);
                    if(attackRange >= (dis + pm.getDistanceFromOthers()))
                    {
                        retPm.add(pm);
                    }
                }
            }
        }
        return retPm;
    }
    
    public ArrayList<AbsPlayerModel> getPmInAttackRange() { return getPmInRange(getAttackRange()); }//except me
    public ArrayList<AbsPlayerModel> getPmInKnowhowRange(KnowhowCard card) { return getPmInRange(CardRule.getCardActiveUseTargetNum(card) + getDistanceFromMe()); }
    
    

    private void onNeedActionByNameInternal(final String name, final IPassAction ipa, final ActionInfo act)
    {
    	IPassAction ipaInternal = new IPassAction() { public void onGotAction(ActionInfo act) {
    		if(act != null)
    			drawCard(act.getCard());
    		ipa.onGotAction(act);
    	}};
    	
    	IPassCard ipc = new IPassCard() { public void onGotCard(Card card) {
    		ActionInfo cardAction = null;
    		if(card != null)
    		{
    			cardAction = new ActionInfo(AbsPlayerModel.this, null, card.getName(), card);
    		}
    		ipa.onGotAction(cardAction);
    	}};
    
    	onNeedActionByName(name, ipc, ipaInternal, act);
    }
    public void onNeedActionByName(final String name, final IPassAction ipa, final ActionInfo act)
    {
    	if(name.equals("闪"))
    	{
    		
    		if(hasEquipment("八卦阵")==true)
    		{
	    		IAskYesNo ask = new IAskYesNo() { public void onResult(boolean yes) {
					if(yes==true)
					{
						IPassCard ipc = new IPassCard() { public void onGotCard(Card card) {
			    			if((PatternCard.isPatternCard(card)==true)&&((PatternCard)card).isRed() == true)
			                {
			    				ipa.onGotAction(new ActionInfo(AbsPlayerModel.this, null, "闪", card));
			                }
			    			else
			    				onNeedActionByNameInternal(name, ipa, act);
			    		}};
			    			
			    		Judge.judge.getOneJudgeCard(new ActionInfo(AbsPlayerModel.this, null, "八卦阵", null), ipc);
					}
					else
						onNeedActionByNameInternal(name, ipa, act);
	    		}};
	    		askYesNo("是否发动八卦阵", ask);
	    		return;
    		}

    	}
    	
    		onNeedActionByNameInternal(name, ipa, act);
    	
    	
    }
    
    
    private void doJudge()
    {
        if(judgeArea.size()!=0)
        {
            final ActionInfo act = judgeArea.get(0);
            judgeArea.remove(act);
            CardHeap.cardHeap.addTrashCard(act.getCard());
            
            IAskYesNo iAsk = new IAskYesNo()
            {
                @Override
                public void onResult(boolean yes)
                {
                    if(act.getActionName().equals("乐不思蜀"))
                    {
                        if(yes==false)
                        {
                            IPassCard ipc = new IPassCard() { public void onGotCard(Card card) {
                                if(!(PatternCard.isPatternCard(card)==true
                                        &&((PatternCard)card).getPattern().getColor()==Pattern.Color.heart))
                                {
                                    Judge.judge.addLog(getCharacterName() + "的乐不思蜀判定生效, 失去出牌阶段");
                                    addJumpStep(PlayerStep.useCards);
                                }
                                else
                                    Judge.judge.addLog(getCharacterName() + "的乐不思蜀判定失效");
                                
                                mHandler.post(new Runnable() { public void run() { doJudge(); } });
                            } };
                            Judge.judge.getOneJudgeCard(act, ipc);
                        }
                        else
                            mHandler.post(new Runnable() { public void run() { doJudge(); } });
                    }
                    else if(act.getActionName().equals("闪电"))
                    {
                        if(yes==false)
                        {
                            IPassCard ipc = new IPassCard() { public void onGotCard(Card card) {
                                int point = 0;
                                if(card != null&&PatternCard.isPatternCard(card)==true
                                        &&((PatternCard)card).getPattern().getColor()==Pattern.Color.spade)
                                    point = ((PatternCard)card).getPattern().getPointsInt();
                                if(point>=2&&point<=9)
                                {
                                    Judge.judge.addLog(getCharacterName() + "的闪电判定生效, 失去三点生命");
                                    onDamage(new Damage(act), null);
                                }
                                else
                                {
                                    AbsPlayerModel pm = Judge.judge.getNextLivePlayerModel();   
                                    Judge.judge.addLog(getCharacterName() + "的闪电判定无效, 闪电传给" + pm.getCharacterName());
                                    act.setTo(pm);
                                    pm.addJudgeArea(act);
                                }
                                if(Judge.judge.isGameEnd()==false)
                                    mHandler.post(new Runnable() { public void run() { doJudge(); } });
                            } };
                            Judge.judge.getOneJudgeCard(act, ipc);
                        }
                        else
                        {
                            AbsPlayerModel pm = Judge.judge.getNextLivePlayerModel();   
                            Judge.judge.addLog(getCharacterName() + "的闪电判定无效, 闪电传给" + pm.getCharacterName());
                            act.setTo(pm);
                            pm.addJudgeArea(act);
                            mHandler.post(new Runnable() { public void run() { doJudge(); } });
                        }
                    }
                }
            };
            Judge.judge.askImpeccable(null, act.getActionName(), this, iAsk);
        }
        else
          Judge.sendStepDoneMsgWithoutDelay(this, waitingExitUseCardsMsg);

    }
    
    
    public void onEnterPlayerStep(PlayerStep playerStep, final Message doneMsg)
    {
        waitingExitUseCardsMsg = null;
        onHintText(null);
        
        if(playerStep==PlayerStep.turnBegin)
        {
            setHasUsedKill(false);
        }
        else if(playerStep==PlayerStep.judge)
        {
            waitingExitUseCardsMsg = doneMsg;
            doJudge();
            return;
            
        }
        else if(playerStep==PlayerStep.receiveCards)
        {
            CardList cards = CardHeap.cardHeap.drawPlayCards(2);
            Judge.judge.addLog(playeView.characterView.getCard().name + "从牌堆里摸了" + cards.size() + "张牌");
            addHandCards(cards);
        }
        else if(playerStep==PlayerStep.useCards)
        {
            waitingExitUseCardsMsg = doneMsg;
            onActiveUseCards();
            return;
        }
        else if(playerStep==PlayerStep.abandonCards)
        {
            int abandonNum = getShouldAbandonCardsNum();
            if(abandonNum!=0)
            {
                final Message msg = doneMsg;
                onHintText("您需要弃" + abandonNum + "张牌");
                selectAbondonCards(getShouldAbandonCardsNum(), new IPassCards()
                {
                    public void onGotCards(CardList cards)
                    {
                        int num = getShouldAbandonCardsNum();
                        if(num>0)
                        {
                            
                            CardList abandonCards = handCards.getUnionCards(cards);
                            
                            while(abandonCards.size()>num)
                                abandonCards.remove(0);

                            while(abandonCards.size()<num)
                                abandonCards.addCards(handCards.getCards(num - cards.size()));
                            
                            drawHandCards(abandonCards);
                            CardHeap.cardHeap.trashPlayCards.addCards(abandonCards);
                            String abandonText = new String();
                            for(int i = 0;i < abandonCards.size();i++)
                            {
                                Card card = abandonCards.get(i); 
                                if(card instanceof PatternCard)
                                {
                                    abandonText += " " + ((PatternCard)card).getPatternText();
                                }
                            }
                            Judge.judge.addLog(playeView.characterView.getCard().name + "弃牌" + abandonText);
                        }
                        Judge.sendStepDoneMsg(AbsPlayerModel.this, msg);
                    }
                });
                return;
            }
        }
        
        Judge.sendStepDoneMsg(this, doneMsg);
    }

    
    public void enterAbandonCards()
    {
        if((Judge.judge.getCurrentTurnPlayer()==this)&&(Judge.judge.getCurrentTurnPlayerStep()==PlayerStep.useCards)
                &&(waitingExitUseCardsMsg!=null))
        {
            Judge.sendStepDoneMsgWithoutDelay(this, waitingExitUseCardsMsg);
        }
    }
    
    public void onActiveUseEquipmentCard(EquipmentCard card)
    {
        getPlayerView().addEquipment(card);
        Judge.judge.addLog(playeView.characterView.getCard().name + "装备" + card.getPatternText());
    }
    
    public void onReplace(Card oldCard)
    {
        CardHeap.cardHeap.trashPlayCards.add(oldCard);
    }
    
    
    
    public void onDamage(Damage damage, Runnable doneR)
    {
    	int lossHealth = damage.getDamage();
        health -= lossHealth;
        playeView.getHealthView().setHealth(health);
        Judge.judge.addLog(getCharacterName() + "受到" + lossHealth + "点伤害");
        if(health<=0)
            Judge.judge.askForPeach(this, doneR);
        else
            Judge.judge.postDone(doneR);
            
    }
    
    public void activeUseCard(Card card, ArrayList<AbsPlayerModel> targetPms, Runnable r)
    {
        if(getWaitingActiveUseDone()==true)
        {
            Judge.judge.postDone(r);
            return;
        }
        
        setWaitingActiveUseDone(true);
        waitingActiveUseDoneRunnable = r;
        if(CardRule.isCardActiveUse(card, this)==false)
        {
            Judge.judge.postDone(r);
            return;
        }
        
        int targetNum = targetPms.size();
        if(targetNum < CardRule.getCardActiveUseTargetNum(card))
        {
            Judge.judge.addLog("缺少目标");
            Judge.judge.postDone(r);
            return;
        }
        
        Runnable doneR = new Runnable() {
            @Override
            public void run() {
                if(waitingActiveUseDoneRunnable!=null)
                    waitingActiveUseDoneRunnable.run();
                waitingActiveUseDoneRunnable = null;
                setWaitingActiveUseDone(false);
            }
        };
        
        drawCard(card);
        
        if(card instanceof EquipmentCard)
        {
            onActiveUseEquipmentCard((EquipmentCard)card);
            Judge.judge.postDone(doneR);
            return;
        }
        
        ActionInfo act = new ActionInfo(this, null, null, card);
        act.addTargetPms(targetPms);
        ArrayList<AbsPlayerModel> targets = act.getTargetPms();
        CardHeap.cardHeap.addTrashCard(card);
        
        if(BaseCard.isBaseCardType(card, BaseCardType.kill)==true)
        {
            act.setActionName("杀");
            Judge.judge.activeAct(act, doneR);
            return;
        }
        else if(card instanceof KnowhowCard)
        {
            if(CardRule.isDelayKnowhowCard((KnowhowCard)card)==true)
            {
            	Judge.judge.addLog(getCharacterName() + "使用" + Card.getCardDescription(card));
                switch (((KnowhowCard)card).getKonwhowType())
                {
                    case lightning:
                        addJudgeArea(new ActionInfo(this, null, "闪电", card));break;
                    case leaveallbehind:
                        AbsPlayerModel target = targets.get(0);
                        target.addJudgeArea(new ActionInfo(this, target, "乐不思蜀", card));
                        break;
                    default:
                        Judge.judge.addLog("未知延时锦囊");break;
                }
            }
            else if(CardRule.isImmediateKnowhowCard((KnowhowCard)card)==true)
            {
                String actName = KnowhowCard.type2String(((KnowhowCard)card).getKonwhowType());
                if(actName!=null&&actName.length()!=0)
                {
                    act.setActionName(actName);
                    Judge.judge.activeAct(act, doneR);
                    return;
                }
                else
                    Judge.judge.addLog("未知锦囊");
                    
            }
        }
        Judge.judge.postDone(doneR);

    }
    
    
}
